package com.jobs.core;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.jobs.core.JobFactory.JobInstanceReplacementException;
import com.jobs.core.exception.JobException;

public final class Engine {
	private static Engine classInstance = new Engine();
	private ExecutorService JOB_EXECUTOR = Executors.newCachedThreadPool();
	private JobFactory jobFactory = JobFactory.getInstance();
	
	private Engine(){
		
	}
	
	public static Engine getInstance() {
		return classInstance;
	}
	
	private void dispatchJob(Job jobInstance){
		JOB_EXECUTOR.execute(jobInstance);		
	}
	
	public void dispatchJob(String jobName) throws UnknownJobRequestException {
		Job jobInstance = jobFactory.getJob(jobName);
		if(jobInstance!=null)
			dispatchJob(jobInstance);
		else{
			throw new UnknownJobRequestException(jobName);
		}
	}

	public void addAndDispatchJob(Job jobInstance) throws JobDispatchException {
		try {
			jobFactory.cacheJobInstance(jobInstance);
			dispatchJob(jobInstance);			
		} catch (JobInstanceReplacementException e) {
			throw new JobDispatchException(e);
		}
	}
	
	public final void shutDown() {
		JOB_EXECUTOR.shutdown();
	}

	//Define all exceptions pumped out from this class
	public static final class JobDispatchException extends JobException {
		private static final long serialVersionUID = 1L;

		public JobDispatchException(String customMessage){
			super(customMessage);
		}

		public JobDispatchException(JobException exe) {
			this("Unable to dispatch job. Failed due to following reason: "+exe.getMessage());
		}		
	}

	public static final class UnknownJobRequestException extends JobException {
		private static final long serialVersionUID = 1L;

		public UnknownJobRequestException(String jobName){
			super("Unknow job "+jobName+" requested for dispatch.");
		}
	}

}